#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <errno.h>
#include <unistd.h>

#define offsetof(s,m) (int)(&(((s*)0)->m))
#define QLEN 10

/*
 * Create a server endpoint of a connection.
 * Returns fd if all OK, <0 on error.
 */
int
unix_listen(const char *name)
{
    int                 fd, len, err, rval;
    struct sockaddr_un  un;

    /* create a UNIX domain stream socket */
    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
       return(-1);
    unlink(name);   /* in case it already exists */

    /* fill in socket address structure */
    memset(&un, 0, sizeof(un));
    un.sun_family = AF_UNIX;
    strcpy(un.sun_path, name);
    len = offsetof(struct sockaddr_un, sun_path) + strlen(name);

    /* bind the name to the descriptor */
    if (bind(fd, (struct sockaddr *)&un, len) < 0) {
        rval = -2;
        goto errout;
    }
    if (listen(fd, QLEN) < 0) { /* tell kernel we're a server */
        rval = -3;
        goto errout;
    }
    return(fd);

errout:
    err = errno;
    close(fd);  
    errno = err;
    return(rval);
}

int unix_accept(int fd, struct sockaddr_un *unix_client_addr, int *client_addr_len)
{
    return accept(fd, (struct sockaddr *)unix_client_addr, (socklen_t *)client_addr_len);
}

int main(int argc, char **argv)
{
    int listen_fd, client_fd;
    char *bind_file;
    struct sockaddr_un client_addr;
    int client_addr_len;

    char buf[4096] = { 0 };
    struct iovec iov[1];       
    struct msghdr msg_hdr;

    int recv_len = 0;

    if (argc != 2)
    {
        printf("Usage: %s bind_file\n", argv[0]);
        exit(0);
    }

    bind_file = argv[1];

    printf("bind_file:%s\n", bind_file);
    if ((listen_fd = unix_listen(bind_file)) < 0)
    {
        printf("unix_listen() fail! ret:%d, errno:%d\n", listen_fd, errno);
        exit(1);
    }

    while (1)
    {
        client_addr_len = sizeof(client_addr); //必须的！否则下面第一次取得的地址将不会正确
        if ((client_fd = unix_accept(listen_fd, &client_addr, &client_addr_len)) < 0)
        {
            printf("unix_accept() fail! errno:%d, error:%s\n", errno, strerror(errno));
            continue;
        }

        printf("recv connect from:[%s]\n", client_addr.sun_path);
        
        //recv msg
        memset(buf, 0, sizeof(buf));
        memset(&msg_hdr, 0, sizeof(msg_hdr));

        iov[0].iov_base = buf;
        iov[0].iov_len  = sizeof(buf);
        msg_hdr.msg_iov     = iov;
        msg_hdr.msg_iovlen  = 1;
        msg_hdr.msg_name    = NULL;
        msg_hdr.msg_namelen = 0;
        msg_hdr.msg_control    = NULL;
        msg_hdr.msg_controllen = 0;
        msg_hdr.msg_flags = 0;

        if ( (recv_len = recvmsg(client_fd, &msg_hdr, 0)) >= 0)
        {
            //假设接收到的是字符串
            printf("recv_len:%d\n", recv_len);
            printf("recvmsg:[%s][len:%d]\n", buf, recv_len);
        }
        else
        {
            printf("recvmsg() error! errno:%d, error:%s\n", errno, strerror(errno));
            close(client_fd);
            continue;
        }

        //send msg
        strcpy(buf, "OK");
        iov[0].iov_base = buf;
        iov[0].iov_len  = strlen(buf);
        msg_hdr.msg_iov     = iov;
        msg_hdr.msg_iovlen  = 1;
        msg_hdr.msg_name    = NULL;
        msg_hdr.msg_namelen = 0;
        msg_hdr.msg_control    = NULL;
        msg_hdr.msg_controllen = 0;
        msg_hdr.msg_flags = 0;

        if (sendmsg(client_fd, &msg_hdr, 0) != strlen(buf))
        {
            printf("sendmsg() error! errno:%d, error:%s\n", errno, strerror(errno));
        }
        else
        {
            printf("sendmsg() success\n");
        } 

        close(client_fd);
    }

    return 0;
}
